<template>
  <div :class="[
    'crud-select',
    `crud-select--${size}`,
    {
      'crud-select--disabled': disabled,
      'crud-select--clearable': clearable,
      'crud-select--multiple': multiple,
      'crud-select--focused': isFocused
    }
  ]">
    <el-select ref="selectRef" v-model="selectValue" v-bind="$attrs" :placeholder="placeholder" :disabled="disabled"
      :clearable="clearable" :multiple="multiple" :multiple-limit="multipleLimit" :size="size" :filterable="filterable"
      :allow-create="allowCreate" :filter-method="filterMethod" :remote="remote" :remote-method="remoteMethod"
      :loading="loading" :loading-text="loadingText" :no-match-text="noMatchText" :no-data-text="noDataText"
      :popper-class="popperClass" :reserve-keyword="reserveKeyword" :default-first-option="defaultFirstOption"
      :teleported="teleported" :automatic-dropdown="automaticDropdown" :fit-input-width="fitInputWidth"
      :suffix-icon="suffixIcon" :tag-type="tagType" :validate-event="validateEvent" class="crud-select__inner"
      @change="handleChange" @visible-change="handleVisibleChange" @remove-tag="handleRemoveTag" @clear="handleClear"
      @blur="handleBlur" @focus="handleFocus">
      <template v-if="$slots.prefix" #prefix>
        <slot name="prefix"></slot>
      </template>

      <template v-if="$slots.empty" #empty>
        <slot name="empty"></slot>
      </template>

      <slot></slot>
    </el-select>
  </div>
</template>

<script setup lang="ts">
import { ref, computed } from 'vue'
import { ElSelect } from 'element-plus'
import { ArrowDown } from '@element-plus/icons-vue'
import type { Component } from 'vue'

/**
 * 下拉框组件属性接口
 */
interface Props {
  /** 绑定值 */
  modelValue?: string | number | boolean | object | Array<string | number | boolean | object>
  /** 占位符文本 */
  placeholder?: string
  /** 是否禁用 */
  disabled?: boolean
  /** 是否可清空 */
  clearable?: boolean
  /** 是否多选 */
  multiple?: boolean
  /** 多选时用户最多可以选择的项目数，为 0 则不限制 */
  multipleLimit?: number
  /** 输入框尺寸 */
  size?: 'large' | 'default' | 'small'
  /** 是否可搜索 */
  filterable?: boolean
  /** 是否允许用户创建新条目 */
  allowCreate?: boolean
  /** 自定义搜索方法 */
  filterMethod?: (query: string) => void
  /** 是否为远程搜索 */
  remote?: boolean
  /** 远程搜索方法 */
  remoteMethod?: (query: string) => void
  /** 是否正在从远程获取数据 */
  loading?: boolean
  /** 远程加载时显示的文字 */
  loadingText?: string
  /** 搜索条件无匹配时显示的文字 */
  noMatchText?: string
  /** 选项为空时显示的文字 */
  noDataText?: string
  /** Select 下拉框的类名 */
  popperClass?: string
  /** 多选且可搜索时，是否在选中一个选项后保留当前的搜索关键词 */
  reserveKeyword?: boolean
  /** 在输入框按下回车，选择第一个匹配项 */
  defaultFirstOption?: boolean
  /** 是否将弹出框插入至 body 元素 */
  teleported?: boolean
  /** 对于不可搜索的 Select，是否在输入框获得焦点后自动弹出选项菜单 */
  automaticDropdown?: boolean
  /** 下拉框的宽度是否与输入框相同 */
  fitInputWidth?: boolean
  /** 自定义后缀图标组件 */
  suffixIcon?: Component
  /** 多选时标签的类型 */
  tagType?: 'success' | 'info' | 'warning' | 'danger'
  /** 是否触发表单验证 */
  validateEvent?: boolean
}

// 定义值类型
type SelectValue = string | number | boolean | object | Array<string | number | boolean | object>

/**
 * 组件事件接口
 */
interface Emits {
  /** 更新绑定值 */
  (e: 'update:modelValue', value: SelectValue): void
  /** 选中值发生变化时触发 */
  (e: 'change', value: SelectValue): void
  /** 下拉框出现/隐藏时触发 */
  (e: 'visible-change', visible: boolean): void
  /** 多选模式下移除tag时触发 */
  (e: 'remove-tag', value: SelectValue): void
  /** 可清空的单选模式下用户点击清空按钮时触发 */
  (e: 'clear'): void
  /** 当 input 失去焦点时触发 */
  (e: 'blur', event: FocusEvent): void
  /** 当 input 获得焦点时触发 */
  (e: 'focus', event: FocusEvent): void
}

// 定义组件属性，设置默认值
const props = withDefaults(defineProps<Props>(), {
  placeholder: '请选择',
  disabled: false,
  clearable: false,
  multiple: false,
  multipleLimit: 0,
  size: 'default',
  filterable: false,
  allowCreate: false,
  remote: false,
  loading: false,
  loadingText: '加载中...',
  noMatchText: '无匹配数据',
  noDataText: '无数据',
  reserveKeyword: true,
  defaultFirstOption: false,
  teleported: true,
  automaticDropdown: false,
  fitInputWidth: false,
  suffixIcon: ArrowDown,
  validateEvent: true
})

// 定义组件事件
const emit = defineEmits<Emits>()

// 下拉框引用
const selectRef = ref<InstanceType<typeof ElSelect>>()

// 焦点状态
const isFocused = ref(false)

// 计算属性：下拉框值
const selectValue = computed({
  get: () => props.modelValue,
  set: (value: SelectValue) => {
    emit('update:modelValue', value)
  }
})

/**
 * 处理值改变事件
 * @param value - 改变后的值
 */
const handleChange = (value: SelectValue): void => {
  emit('change', value)
}

/**
 * 处理下拉框显示/隐藏事件
 * @param visible - 是否显示
 */
const handleVisibleChange = (visible: boolean): void => {
  emit('visible-change', visible)
}

/**
 * 处理移除标签事件
 * @param value - 移除的值
 */
const handleRemoveTag = (value: SelectValue): void => {
  emit('remove-tag', value)
}

/**
 * 处理清空事件
 */
const handleClear = (): void => {
  emit('clear')
}

/**
 * 处理失去焦点事件
 * @param event - 焦点事件
 */
const handleBlur = (event: FocusEvent): void => {
  isFocused.value = false
  emit('blur', event)
}

/**
 * 处理获得焦点事件
 * @param event - 焦点事件
 */
const handleFocus = (event: FocusEvent): void => {
  isFocused.value = true
  emit('focus', event)
}

/**
 * 获取焦点
 */
const focus = (): void => {
  selectRef.value?.focus()
}

/**
 * 失去焦点
 */
const blur = (): void => {
  selectRef.value?.blur()
}

// 暴露方法给父组件
defineExpose({
  focus,
  blur
})
</script>

<style lang="scss" scoped>
.crud-select {
  position: relative;
  display: inline-block;
  width: 100%;

  // 尺寸样式
  &--large {
    .crud-select__inner {
      :deep(.el-select__wrapper) {
        height: 40px;
        font-size: 16px;
      }
    }
  }

  &--default {
    .crud-select__inner {
      :deep(.el-select__wrapper) {
        height: 32px;
        font-size: 14px;
      }
    }
  }

  &--small {
    .crud-select__inner {
      :deep(.el-select__wrapper) {
        height: 24px;
        font-size: 12px;
      }
    }
  }

  // 状态样式
  &--disabled {
    .crud-select__inner {
      :deep(.el-select__wrapper) {
        background-color: #e0e0e0;
        border: none;
        cursor: not-allowed;
        box-shadow: none;

        .el-select__selected-item {
          color: #666666;
          font-family: inherit;
        }

        .el-select__placeholder {
          color: #666666;
          font-family: inherit;
        }

        .el-select__suffix {
          color: #666666;
        }
      }
    }
  }

  &--focused {
    .crud-select__inner {
      :deep(.el-select__wrapper) {
        background-color: #f5f5f5;
        border: none;
        box-shadow: none;
      }
    }
  }

  // 内部选择器样式
  &__inner {
    width: 100%;

    :deep(.el-select__wrapper) {
      border-radius: 6px;
      border: none;
      background-color: #f5f5f5;
      transition: all 0.2s ease;
      padding: 0 12px;
      box-shadow: none;
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;

      &:hover:not(.is-disabled) {
        background-color: #f5f5f5;
        border: none;
        box-shadow: none;
      }

      &.is-focused {
        background-color: #f5f5f5;
        border: none;
        box-shadow: none;
      }

      .el-select__selected-item {
        color: #000000;
        font-family: inherit;
      }

      .el-select__placeholder {
        color: #000000;
        font-family: inherit;
      }

      .el-select__suffix {
        color: #000000;

        .el-select__caret {
          transition: transform 0.2s ease;
          color: #000000;
        }

        &.is-reverse .el-select__caret {
          transform: rotate(180deg);
        }
      }

      .el-select__input {
        color: #000000;
        font-family: inherit;

        &::placeholder {
          color: #000000;
        }
      }
    }

    // 多选标签样式
    :deep(.el-tag) {
      background-color: #e0e0e0;
      border: none;
      color: #000000;
      border-radius: 4px;
      font-family: inherit;

      .el-tag__close {
        color: #000000;

        &:hover {
          background-color: #cccccc;
          color: #000000;
        }
      }

      &.el-tag--success {
        background-color: #e0e0e0;
        border: none;
        color: #000000;

        .el-tag__close {
          color: #000000;

          &:hover {
            background-color: #cccccc;
            color: #000000;
          }
        }
      }

      &.el-tag--warning {
        background-color: #e0e0e0;
        border: none;
        color: #000000;

        .el-tag__close {
          color: #000000;

          &:hover {
            background-color: #cccccc;
            color: #000000;
          }
        }
      }

      &.el-tag--danger {
        background-color: #e0e0e0;
        border: none;
        color: #000000;

        .el-tag__close {
          color: #000000;

          &:hover {
            background-color: #cccccc;
            color: #000000;
          }
        }
      }

      &.el-tag--info {
        background-color: #e0e0e0;
        border: none;
        color: #000000;

        .el-tag__close {
          color: #000000;

          &:hover {
            background-color: #cccccc;
            color: #000000;
          }
        }
      }
    }
  }
}

// 深色模式适配
@media (prefers-color-scheme: dark) {
  .crud-select {
    &--disabled {
      .crud-select__inner {
        :deep(.el-select__wrapper) {
          background-color: $bg-color-gray-dark;
          border-color: $border-color-lighter-dark;
          box-shadow: none;

          .el-select__selected-item,
          .el-select__placeholder,
          .el-select__suffix {
            color: $text-color-disabled-dark;
            font-family: inherit;
          }
        }
      }
    }

    &__inner {
      :deep(.el-select__wrapper) {
        background-color: $bg-color-card-dark;
        border: 1px solid $border-color-base-dark;
        box-shadow: none;

        &:hover:not(.is-disabled) {
          background-color: $hover-bg-light-dark;
          border-color: var(--primary-color-light, $primary-color-light);
        }

        &.is-focused {
          border-color: var(--primary-color, $primary-color);
        }

        .el-select__selected-item,
        .el-select__placeholder,
        .el-select__suffix,
        .el-select__input {
          color: $text-color-primary-dark;
          font-family: inherit;
        }

        .el-select__suffix .el-select__caret {
          color: $text-color-primary-dark;
        }

        .el-select__input::placeholder {
          color: $text-color-muted-dark;
        }
      }
    }
  }
}
</style>
